<?php

namespace Alipay\Common;


class CertClient
{
    //支付宝根证书
    protected $alipayRootCert;

    private $alipayRootCertSN;

    //支付宝公钥证书
    protected $alipayPublicCert;
    private $alipayPublicCertSN;

    //应用公钥证书
    protected $appPublicCert;
    private $appPublicCertSN;

    public $isCertModel = true;

    /**
     * @param mixed $alipayRootCert
     */
    public function setAlipayRootCert($alipayRootCert): self
    {
        $this->alipayRootCert = $alipayRootCert;
        $this->getAlipayRootCert();
        return $this;
    }

    /**
     * @param mixed $alipayPublicCert
     */
    public function setAlipayPublicCert($alipayPublicCert): self
    {
        $this->alipayPublicCert = $alipayPublicCert;
        $this->getAlipayPublicCert();
        return $this;
    }

    /**
     * @param mixed $appPublicCert
     */
    public function setAppPublicCert($appPublicCert): self
    {
        $this->appPublicCert = $appPublicCert;
        $this->getAppPublicCert();
        return $this;
    }

    /**
     * @return mixed
     */
    public function getAlipayRootCertSN()
    {
        return $this->alipayRootCertSN;
    }

    /**
     * @return mixed
     */
    public function getAlipayPublicCertSN()
    {
        return $this->alipayPublicCertSN;
    }

    /**
     * @return mixed
     */
    public function getAppPublicCertSN()
    {
        return $this->appPublicCertSN;
    }


    private function getAppPublicCert()
    {
        $this->appPublicCert = file_get_contents($this->appPublicCert);

        if (!$this->appPublicCert) {
            $this->isCertModel = false;
            return;
        }
        $ssl = openssl_x509_parse($this->appPublicCert);
        $this->appPublicCertSN = md5($this->arrayToString(array_reverse($ssl['issuer'])) . $ssl['serialNumber']);
    }

    private function getAlipayRootCert()
    {
        $this->alipayRootCert = file_get_contents($this->alipayRootCert);

        if (!$this->alipayRootCert) {
            $this->isCertModel = false;
            return;
        }
        $array = explode("-----END CERTIFICATE-----", $this->alipayRootCert);
        $SN = null;
        for ($i = 0; $i < count($array) - 1; $i++) {
            $ssl[$i] = openssl_x509_parse($array[$i] . "-----END CERTIFICATE-----");
            if (strpos($ssl[$i]['serialNumber'], '0x') === 0) {
                $ssl[$i]['serialNumber'] = $this->hex2dec($ssl[$i]['serialNumberHex']);
            }
            if ($ssl[$i]['signatureTypeLN'] == "sha1WithRSAEncryption" || $ssl[$i]['signatureTypeLN'] == "sha256WithRSAEncryption") {
                if ($SN == null) {
                    $SN = md5($this->arrayToString(array_reverse($ssl[$i]['issuer'])) . $ssl[$i]['serialNumber']);
                } else {

                    $SN = $SN . "_" . md5($this->arrayToString(array_reverse($ssl[$i]['issuer'])) . $ssl[$i]['serialNumber']);
                }
            }
        }
        $this->alipayRootCertSN = $SN;
    }

    private function getAlipayPublicCert()
    {
        $this->alipayPublicCert = file_get_contents($this->alipayPublicCert);

        if (!$this->alipayPublicCert) {
            $this->isCertModel = false;
            return;
        }
        $pkey = openssl_pkey_get_public($this->alipayPublicCert);
        $keyData = openssl_pkey_get_details($pkey);
        $public_key = str_replace('-----BEGIN PUBLIC KEY-----', '', $keyData['key']);
        $this->alipayPublicCertSN = trim(str_replace('-----END PUBLIC KEY-----', '', $public_key));
    }

    private function arrayToString($array): string
    {
        $string = [];
        if ($array && is_array($array)) {
            foreach ($array as $key => $value) {
                $string[] = $key . '=' . $value;
            }
        }
        return implode(',', $string);
    }

    /**
     * 0x转高精度数字
     * @param $hex
     * @return int|string
     */
    private function hex2dec($hex)
    {
        $dec = 0;
        $len = strlen($hex);
        for ($i = 1; $i <= $len; $i++) {
            $dec = bcadd($dec, bcmul(strval(hexdec($hex[$i - 1])), bcpow('16', strval($len - $i))));
        }

        return $dec;
    }

}